步骤 3:为库添加使用要求¶
练习 1 - 为库添加使用要求¶
目标的使用要求 参数可以更好地控制库或可执行文件的链接和包含行,同时也能更好地控制 CMake 内部目标的传递属性。利用使用要求的主要命令有:
目标¶
为库添加使用要求。
有用的材料¶
要编辑的文件¶
MathFunctions/CMakeLists.txt
CMakeLists.txt
开始入门¶
在本练习中,我们将重构来自 Adding a Library
的代码,以使用现代 CMake 方法。我们将让库定义自己的使用要求,以便它们在必要时传递给其他目标。在本例中,MathFunctions
将自行指定任何需要的包含目录。然后,使用方目标 Tutorial
只需要链接到 MathFunctions
,而无需担心任何额外的包含目录。
起始源代码在 Step3
目录中提供。在本练习中,完成 TODO 1
到 TODO 3
。
首先,在 MathFunctions/CMakeLists
中添加对 target_include_directories()
的调用。请记住,CMAKE_CURRENT_SOURCE_DIR
是当前正在处理的源目录的路径。
然后,更新(并简化!)顶层 CMakeLists.txt
中对 target_include_directories()
的调用。
构建和运行¶
创建一个名为 Step3_build
的新目录,运行 cmake
可执行文件或 cmake-gui
来配置项目,然后使用您选择的构建工具或通过使用 cmake --build .
从构建目录构建它。以下是从命令行执行此操作的步骤回顾
mkdir Step3_build
cd Step3_build
cmake ../Step3
cmake --build .
接下来,使用新构建的 Tutorial
并验证它是否按预期工作。
解决方案¶
让我们更新上一步的代码,以使用现代 CMake 的使用要求方法。
我们想要声明任何链接到 MathFunctions
的人都需要包含当前源目录,而 MathFunctions
本身则不需要。这可以用 INTERFACE
使用要求来表示。记住 INTERFACE
意味着消费者需要但生产者不需要的东西。
在 MathFunctions/CMakeLists.txt
的末尾,使用带有 INTERFACE
关键字的 target_include_directories()
,如下所示
TODO 1:点击显示/隐藏答案
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
现在我们已经为 MathFunctions
指定了使用要求,我们可以安全地从顶层 CMakeLists.txt
中删除我们对 EXTRA_INCLUDES
变量的使用。
删除此行
TODO 2:点击显示/隐藏答案
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
并从 target_include_directories
中删除 EXTRA_INCLUDES
TODO 3:点击显示/隐藏答案
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
请注意,使用此技术,我们的可执行目标使用库的唯一操作是调用带有库目标名称的 target_link_libraries()
。在较大的项目中,手动指定库依赖项的经典方法很快就会变得非常复杂。
练习 2 - 使用接口库设置 C++ 标准¶
现在我们已经将代码切换到更现代的方法,让我们演示一种现代技术来为多个目标设置属性。
让我们重构现有代码以使用 INTERFACE
库。我们将在下一步中使用该库来演示 generator expressions
的常见用法。
目标¶
添加一个 INTERFACE
库目标以指定所需的 C++ 标准。
有用的资源¶
要编辑的文件¶
CMakeLists.txt
MathFunctions/CMakeLists.txt
开始入门¶
在本练习中,我们将重构我们的代码以使用 INTERFACE
库来指定 C++ 标准。
从我们在步骤 3 练习 1 结束时留下的内容开始此练习。您将必须完成 TODO 4
到 TODO 7
。
首先编辑顶层 CMakeLists.txt
文件。构建一个名为 tutorial_compiler_flags
的 INTERFACE
库目标,并将 cxx_std_11
指定为目标编译器功能。
修改 CMakeLists.txt
和 MathFunctions/CMakeLists.txt
,以便所有目标都具有对 tutorial_compiler_flags
的 target_link_libraries()
调用。
构建和运行¶
由于我们已经从练习 1 配置了构建目录,因此只需通过调用以下命令重新构建代码即可
cd Step3_build
cmake --build .
接下来,使用新构建的 Tutorial
并验证它是否按预期工作。
解决方案¶
让我们更新上一步的代码,以使用接口库来设置我们的 C++ 要求。
首先,我们需要删除对变量 CMAKE_CXX_STANDARD
和 CMAKE_CXX_STANDARD_REQUIRED
的两个 set()
调用。要删除的具体行如下
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
接下来,我们需要创建一个接口库 tutorial_compiler_flags
。然后使用 target_compile_features()
添加编译器功能 cxx_std_11
。
TODO 4:点击显示/隐藏答案
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
最后,在设置好接口库后,我们需要将我们的可执行文件 Tutorial
、我们的 SqrtLibrary
库和我们的 MathFunctions
库链接到我们新的 tutorial_compiler_flags
库。相应地,代码将如下所示
TODO 5:点击显示/隐藏答案
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
这个
TODO 6:点击显示/隐藏答案
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
和这个
TODO 7:点击显示/隐藏答案
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
有了这个,我们所有的代码仍然需要 C++ 11 才能构建。但请注意,使用此方法,我们可以具体说明哪些目标获得特定要求。此外,我们在接口库中创建了一个单一的事实来源。